package com.webex.ta.hydra.core.engine;

import com.webex.ta.hydra.core.*;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-8-19
 * Time: 13:18:45
 */
public class DefaultHydraEngine implements HydraEngine {
    private static final long WAIT_TO_DIE = 5 * 1000;

    private TestPlan tp;
    private Thread thread;
    private HydraThread runnable;
    private boolean debug;

    private List<TestListener> testListeners;
    private List<HydraActionListener> actionListeners;
    private List<HydraAssertionListener> assertionListeners;

    private DefaultHydraEngine() {
        this(null);
    }

    public DefaultHydraEngine(TestPlan tp) {
        this.tp = tp;
        debug = true;
        testListeners = new ArrayList<TestListener>();
        actionListeners = new ArrayList<HydraActionListener>();
        assertionListeners = new ArrayList<HydraAssertionListener>();
    }

    public void configureWithTestPlan(TestPlan tp) {
        this.tp = tp;
    }

    public void turnOnDebug() {
        debug = true;
    }

    public void turnOffDebug() {
        debug = false;
    }

    public void addTestListener(TestListener listener) {
        testListeners.add(listener);
    }

    public void removeTestListener(TestListener listener) {
        testListeners.remove(listener);
    }

    public void addActionListener(HydraActionListener listener) {
        actionListeners.add(listener);
    }

    public void removeActionListener(HydraActionListener listener) {
        actionListeners.remove(listener);
    }

    public void addAssertionListener(HydraAssertionListener listener) {
        assertionListeners.add(listener);
    }

    public void notifyTestListenersOfBeforeStart() {
        for (TestListener testListener : testListeners) {
            testListener.beforeTestStart();
        }
    }

    public void notifyTestListenersOfStart(HydraThread source) {
        for (TestListener testListener : testListeners) {
            testListener.testStarted(source);
        }
    }

    public void notifyTestListenersOfPause(HydraThread source) {
        for (TestListener testListener : testListeners) {
            testListener.testPaused(source);
        }
    }

    public void notifyTestListenersOfResume(HydraThread source) {
        for (TestListener testListener : testListeners) {
            testListener.testResumed(source);
        }
    }

    public void notifyTestListenersOfEnd(HydraThread source) {
        for (TestListener testListener : testListeners) {
            testListener.testEnded(source);
        }
    }

    public void notifyActionListenerOfOccured(TestResult result) {
        for (HydraActionListener listener : actionListeners) {
            listener.actionOccured(result);
        }
    }

    public void notifyAssertionListenerOfOccured(AssertionResult ar) {
        for (HydraAssertionListener listener : assertionListeners) {
            listener.assertionOccured(ar);
        }
    }


    public void run() {
        runnable = new HydraThread();
        runnable.configure(tp);
        runnable.setEngine(this);
        if (debug) {
            runnable.turnOnDebugMode();
        }
        thread = new Thread(runnable);
        notifyTestListenersOfBeforeStart();
        thread.start();
    }

    public void stop() {
        Thread stopThread = new Thread(new StopTest());
		stopThread.start();
    }

    public void pause() {

    }

    public void resume() {
        runnable.resume();
    }

    private class StopTest implements Runnable {
        boolean now;

        private StopTest() {
            now = true;
        }

        private StopTest(boolean b) {
            now = b;
        }

        public void run() {
            tellThreadToStop();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
            boolean stopped = verifyThreadsStopped();
            if (stopped || now) {
                notifyTestListenersOfEnd(runnable);
            }
        }
    }


    private void tellThreadToStop() {
        runnable.stop();
        System.out.println("Stop " + thread.getName());
        thread.stop();
//        thread.interrupt();
    }


    private boolean verifyThreadsStopped() {
        boolean stopped = true;
        if (thread != null && thread.isAlive()) {
            try {
                thread.join(WAIT_TO_DIE);
            } catch (InterruptedException e) {
            }
            if (thread.isAlive()) {
                stopped = false;
            }
            System.out.println(stopped);
        }
        return stopped;
    }

}




